﻿#pragma once


#include "Reflection/ReflectableInterface.h"
#include "Reflection/Reflection.h"
#include "Reflection/Class.h"

#include "Containers/Flags.h"
#include "Containers/Vector.h"

#include "Misc/Guid.h"

#include "ObjectHead.h"


#ifdef USING_SOURCE_LOCATION
	#include <source_location>
#endif

#include "ObjectM.h"  

//forward declarations
class CScriptContent;
namespace WH
{
	WHENGINE_API void DestroyObject(RObject* InObject);
};

struct SAssetPath;
class RObjectComponent;


//Base class of all engine object
//there is a object tree in engine, every object is a node in the tree
//the root node is empty object named "Root"
//object's parent node is called owner
//object's child node is called children
//if object is destroyed, all its children will be destroyed.
RCLASS__OF_ROBJECT()
class WHENGINE_API RObject:public IReflectable
{
	ROBJECT_OF_ROBJECT

	SObjectHead* GetObjectHead() const ;

#ifdef USING_SOURCE_LOCATION
	std::source_location CreatePosition;
#endif
	SObjectHead* SelfHead = nullptr;

	//该对象引用的对象
	//这是一个临时变量，用于GC算法
	//temporary store referenced object by GC algorithm
	//TVector<RObject*> GCReferencedObjects;
	TForwardForwardLinkedList<RObject*> GCReferencedObjects;
	//该对象被引用的次数
	//这是一个临时变量，用于GC算法
	uint32_t GCReference=0;
	//该对象是否可达
	//这是一个临时变量，用于GC算法
	bool bGCReachable=false;

public:
	RObject();
	virtual ~RObject();
	
	//第一次创建对象时调用
	//如果对象是从资源加载的，视为第二次创建，这个函数不会被调用
	virtual void FirstTimeInitializeObject() {};

	//如果对象是从资源加载的，这个函数会被调用
	virtual void PostLoadFromAsset() {};
private:
	friend void WH::DestroyObject(RObject *InObject);

public:
	template<typename T>
	bool IsA()
	{
		return IsA(T::StaticClass());
	}

	bool IsA(CClass* InClass)
	{
		if(GetClass()==InClass)
		{
			return true;
		}
		return GetClass()->IsDescendantOf(InClass);
		
	}

//对象树相关：
//对象之间的父子关系，决定了对象的销毁顺序
//在销毁对象时，会自动销毁子对象
public:
	//获取父对象
	RObject* GetOwner() const { return GetObjectHead()->Owner.Get(); }
	//设置父对象
	void SetOwner(RObject* InOwner);
	//获取子对象列表
	const TVector<RObject*>& GetChildren() const { return GetObjectHead()->Children; }

	//获取对象在对象树中的名字
	CString GetNodeName() const;
	//设置对象在对象树中的名字
	void SetNodeName(const CString& InNodeName);

	//根据名字查找子对象
	virtual RObject* FindChild(const CString& InNodeName);

	//获取对象在对象树中的路径
	//格式为： 爷爷的名字;父亲的名字;自己的名字
	CString GetPath() const;

	//获取对象的原始名字， 对象名字=对象名字=原始名字_后缀
	CString GetRawName();
	
	//设置对象的原始名字, 对象名字=对象名字=原始名字_后缀
	void SetRawName(CString InRawName);

	//获取对象的后缀,后缀是为了保证对象在同一个父对象下的名字唯一
	//后缀是一个数字， 对象名字=原始名字_后缀
	uint32_t GetNamePostfix() const { return GetObjectHead()->NamePostfix; }

	//获取资产路径
	virtual const SAssetPath* GetAssetPath() const;

protected:
	//在子对象列表中移除子对象
	virtual void RemoveChildFromChildren(RObject* Child);
	//在子对象列表中添加子对象
	virtual void AddChildToChildren(RObject* Child);
	//生成一个唯一后缀确保子对象名字唯一
	virtual void MakeSureChildNameUnique(RObject* Child);


//脚本相关：
public:
	CScriptContent* GetScriptContent() const { return _ScriptContent; }
	void SetScriptContent(CScriptContent* InScriptContent) { _ScriptContent= InScriptContent; }
private:
	//如果脚本继承了这个类
	//那么这里就是脚本的扩展
	CScriptContent* _ScriptContent=nullptr;   

public:
	//将对象转换为字符串
	//用于脚本,所有的类型都有ToString函数
	virtual CString ToString();

//引用相关：
//引用关系用于垃圾回收和资产管理
    virtual void GetReferencedObjects(TForwardForwardLinkedList<RObject *> &OutReferencedObjects);

};


class RRootObject;

namespace WH
{

    //the root object is the owner of all asset object 
    WHENGINE_API RRootObject* GetRootObject();

	//the transient asset is the owner of all transient objects
	//all most all objects are transient objects
	//except objects that loaded from asset file
	//if NewObject() without owner, the owner will be transient asset
	//only allow it's subobject is created in main thread

	//why we need transient asset?
	//because asset system require load asset object from asset in worker thread, it's owner is root object
	//if user create object in main thread and owner is root object, it will cause data race 
	WHENGINE_API RObject* GetTransientAsset();


    //if want to destroy more than one objects , use DestroyObject() is dangerous
    //because it will auto destroy sub objects of the object
    //then if you invoke DestroyObject() with a destroyed sub object, it will crash
    //use DestroyObjects() to destroy more than one objects
    WHENGINE_API void DestroyObject(RObject* InObject);

    //destroy more than one objects
    WHENGINE_API void DestroyObjects(const TVector<RObject*>& InObjects);

}